yield的中文翻譯有很多意思,在程式裡可以翻做「讓」的意思。
那在程式裡,到底是「讓」出什麼東西呢?
p.s不知道為何打到這裡腦袋突然出現扶老太太過馬路
下面例子say_something方法,下方有個掛載的block,yield的作用就是「將控制權暫時讓給Block」之後,再繼續回來執行程式。
def say_something
puts 'This is start'
yield
puts 'This is end'
end
say_something { puts 'Block aboard!'}
# => This is start
# Block aboard!
# This is end
程式執行的流程:
從第2行印出'This is start',再往下時遇到yield,暫時將控制權移交給第7行印出'Block aboard!'後,又回到第4行印出'This is end'。
下面例子其實跟上面雷同,只是多一個class而已。
class Hero
def heart_beating
yield
end
end
king = Hero.new
king.heart_beating { p '帝王引擎' }
# => 帝王引擎
在yield的後面可以自帶參數,延續上面的例子
class Hero
def heart_beating
yield
end
def one_punch
yield '反覆橫跳'
end
end
king = Hero.new
king.heart_beating { p '帝王引擎' }
# => 帝王引擎
saitama = Hero.new
saitama.one_punch {|skill| p "必殺認真系列..#{skill}" }
# => "必殺認真系列..反覆橫跳"
class Hero
def heart_beating
yield
end
def one_punch
yield '反覆橫跳'
yield '連續普通拳'
yield '認真拳'
end
end
king = Hero.new
king.heart_beating { p '帝王引擎' }
# => 帝王引擎
saitama = Hero.new
saitama.one_punch {|skill| p "必殺認真系列..#{skill}" }
# => "必殺認真系列..反覆橫跳"
# "必殺認真系列..連續普通拳"
# "必殺認真系列..認真拳"
Ruby有內建一個方法 block_given?
def optional_block
yield('還我漂漂拳') if block_given?
end
p optional_block # => nil
optional_block {|x| puts "#{x}" } # => 還我漂漂拳
如果有給block,就yield控制權出去給block。
def calculator(a, b)
yield(a, b)
end
puts calculator(5, 6) { |a, b| a + b } # => 11
puts calculator(5, 6) { |a, b| a - b } # => -1
def yield_with_arguments
yield "巴達獸進化~~~~~~~"
last_name = 'John'
first_name = 'Cena'
yield(last_name, first_name)
end
yield_with_arguments { |l, f| puts "#{l} #{f}" }
# => 巴達獸進化~~~~~~~
# John Cena
範例一:
第7行的i
被yeild出去找了第11行的i,x
則是實體變數@v
用each方法印出陣列中的數字。
class Map
def initialize
@v = [1, 2, 3, 4]
end
def each_print
@v.each{|i| puts yield i } if block_given?
end
end
i = "I can count number"
a_obj = Map.new
a_obj.each_print{|x| "#{i} #{x} " }
# =>
# I can count number 1
# I can count number 2
# I can count number 3
# I can count number 4
範例二:
針對第4行中的counter去yield給method外部的block,且first給預設值=1。可以看到給first參數值,在第4行的counter就會走block中的方式,且從給的值開始往下走。
(備註:next方法可以找下一個數字或字母)
def list(array, first = 1)
counter = first
array.each do |item|
puts "#{yield counter}. #{item}"
counter = counter.next
end
end
list(["a","b","c"]) { |ary| ary }
list(["a","b","c"], 100) { |ary| ary }
list(["Ruby", "Is", "Fun"], "A") { |ary| ary }
#output
# 1. a
# 2. b
# 3. c
# 100. a
# 101. b
# 102. c
# A. Ruby
# B. Is
# C. Fun
yield就是暫時把控制權交棒給method外的 Block,等 Block 執行結束後再把控制權交回來method,並繼續往下走到程式結束。
yield的使用時機,可能因為做的練習跟專案還不夠多,暫時還不確定到底會在哪個情境使用到yield,但可以從上面幾的範例感受到,如果要針對method內某個變數的值去做改變的話,可用yield的方式將控制權讓出給寫在method外的block去做運算。
參考資料:
I don't really understand what is this yield
Blocks and yields in Ruby
Mastering Ruby Blocks in Less Than 5 Minutes
The Ultimate Guide to Blocks, Procs & Lambdas
The yield Keyword in Ruby
為自己學Ruby on Rails
活用Ruby裡的yield
“Most of the important things in the world have been accomplished by people who have kept on trying when there seemed to be no hope at all.”
– Dale Carnegie, Motivational Expert
本文同步發佈於: https://louiswuyj.tw/